﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Xml;
using System.Threading;
using System.IO;
using System.Text.RegularExpressions;

namespace iReaper.IndexBuilder.WWESource
{
    class WWEDetailCrawler
    {
        private int _iFlag;
        private AutoResetEvent _completEvent;
        private bool _isRunning;
        private int _iCount;
        private Semaphore semaphore;

        private void Init()
        {
            _iFlag = 0;
            _completEvent = new AutoResetEvent(false);
            _isRunning = true;
            _iCount = 0;
            semaphore = new Semaphore(10, 10);
        }

        public void Process(ChannelInfo[] infos)
        {
            if (null == infos)
            {
                throw new ArgumentNullException("infos");
            }

            if (_isRunning)
            {
                throw new ApplicationException("This crawler is in use.");
            }

            Init();
            
            int i = 0;
            foreach (ChannelInfo info in infos)
            {
                foreach (ChannelInfoItem channelItem in info.Items)
                {
                    foreach (EventItem item in channelItem.Events)
                    {
                        Console.Write("{0} details issued\r", i++);
                        Thread.Sleep(300);
                        semaphore.WaitOne();

                        WebClient client = new WebClient();
                        client.Encoding = System.Text.Encoding.UTF8;
                        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(OnPageBack);
                        Interlocked.Increment(ref _iFlag);
                        client.DownloadStringAsync(new Uri(item.DetailUrl), item);
                    }
                }
            }
            if (i > 0)
            {
                _completEvent.WaitOne();
            }

        }

        private void OnPageBack(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                if (e.Cancelled || e.Error != null)
                {
                    return;
                }
                
                
                EventItem item = e.UserState as EventItem;
                if (null == item)
                {
                    throw new InvalidOperationException();
                }

                Sgml.SgmlReader reader = new Sgml.SgmlReader();
                reader.InputStream = new StringReader(System.Web.HttpUtility.HtmlDecode(e.Result));

                string xml = reader.ReadOuterXml().Trim() ;
                XmlDocument xmldoc = new XmlDocument();
                xmldoc.LoadXml(xml);
                // Get title
                XmlNode titleNode = xmldoc.SelectSingleNode(".//title");
                if (titleNode != null && string.IsNullOrEmpty(item.Title))
                {
                    item.Title = titleNode.InnerText;
                }
                // Get Url
                XmlNode urlNode = xmldoc.SelectSingleNode(".//TD[@id='UCActionbar_tdRegOnline']");
                XmlNode descNode = xmldoc.SelectSingleNode(".//SPAN[@id='eventInfo_lblEventDescription']");

                if (urlNode == null || descNode == null)
                {
                    return;
                }

                item.DownloadUrl = urlNode.SelectSingleNode(".//a").Attributes["href"].Value;
                ParseDescXml(descNode, item);
            }
            finally
            {
                int flag = Interlocked.Decrement(ref _iFlag);
                if (flag == 0)
                {
                    // Complete this batch
                    _completEvent.Set();
                    _isRunning = false;
                }
                int iCount = Interlocked.Increment(ref _iCount);
                semaphore.Release();
                Console.Write(iCount + "\r");
            }
        }

        private void ParseDescXml(XmlNode descNode, EventItem item)
        {
            XmlNodeList nPs = descNode.SelectNodes(".//P");
            XmlNodeList nDivs = descNode.SelectNodes(".//DIV");

            // There are only two <P> element
            System.Diagnostics.Debug.Assert(nPs.Count == 2);
            string description = nPs[0].InnerText;
            item.Description = description;
            string presenterString = nPs[1].InnerText;

            Match match = reg.Match(presenterString);
            if (!match.Success)
            {
                return;
            }

            // Get intros
            System.Diagnostics.Debug.Assert(nDivs.Count > 2);
            XmlNodeList nIntros = nDivs[0].SelectSingleNode("FONT").SelectNodes("text()");
            

            CaptureCollection names = match.Groups["Name"].Captures;
            CaptureCollection titles = match.Groups["Title"].Captures;

            int length = names.Count;
            // there should be enough cvs
            
            List<Author> authors = new List<Author>();
            for (int i = 0; i < length; i++)
            {
                string name = names[i].Value;
                string title = titles[i].Value;

                Author author = new Author();
                author.Name = name.Replace("and","").Trim();
                author.Title = title;
                if (nIntros.Count >= length)
                {
                    author.Introduce = nIntros[i].InnerText;
                }

                authors.Add(author);
            }

            item.Authors = authors.ToArray();

            // <P>...</P> Description
            // <P>...</P> Presenter
            // <DIV> ... </DIV> first presenter's cv
        }

        const string regex = "Presenter:\\s+((?<Name>[\\w ]+)\\s*,(?<Title>[\\w ]+\\s*,[\\w ]+)\\s*,?)*";
        static System.Text.RegularExpressions.RegexOptions options = (((System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace | System.Text.RegularExpressions.RegexOptions.Singleline)
                    | System.Text.RegularExpressions.RegexOptions.ExplicitCapture)
                    | System.Text.RegularExpressions.RegexOptions.Multiline);
        static System.Text.RegularExpressions.Regex reg = new System.Text.RegularExpressions.Regex(regex, options);

        
    }
}
